﻿/* 
 *  <copyright file="CGuid.cs" company="Wesley Jowitt">
 *  
 *  SobrietyEngine: Copyright (c) 2011 Wesley Jowitt
 *  
 *  This software is distributed under a software license.
 *   * As of the creation time of this file, the license in use is the Microsoft Permissive License (Ms-PL) 
 *    * The license can be viewed at:
 *     * License.Txt in the root folder of this project
 *      * http://sobrietyengine.codeplex.com/license
 *       * http://www.microsoft.com/opensource/licenses.mspx
 *       
 *  </copyright>
 *   */

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;

namespace SobrietyEngine.UDMF
{
    public class UDMFMap
    {
        public List<Vertex> Verts { get; set; }
        public List<Linedef> Linedefs { get; set; }
        public List<Thing> Things { get; set; }
        public List<Sector> Sectors { get; set; }
        public List<Sidedef> Sidedefs { get; set; }
        public Vector3 Scale { get; set; }

        public UDMFMap()
        {
            Verts = new List<Vertex>();
            Linedefs = new List<Linedef>();
            Things = new List<Thing>();
            Sectors = new List<Sector>();
            Sidedefs = new List<Sidedef>();

            Scale = Vector3.One;
        }

        public void Compile()
        {
            //actualy link all objects togehter, instead through indexes. 
            //specifically, need to link sectors to vertecies for creating polygons.
            //currently, we have: frontVerts to verts, frontVerts to sidedefs
            //sidedefs to sectors

            //for the 2d game stuff, id like to be able to create polygons based on sectors
            //lets link sectors to verts, for now.

            //get lindef info into side defs
            foreach (Linedef ld in Linedefs)
            {
                if(ld.SidedefBackIndex != -1)
                    Sidedefs[ld.SidedefBackIndex].Linedefs.Add(ld);
                if(ld.SidedefFrontIndex != -1)
                    Sidedefs[ld.SidedefFrontIndex].Linedefs.Add(ld);
            }

            //get sidedef info into sector.
            foreach (Sidedef sd in Sidedefs)
            {
                Sectors[sd.SectorIndex].Sidedefs.Add(sd);
            }

            //go through each sector, and make an order list of verts
            foreach (Sector s in Sectors)
            {
                //get all of our linedefs
                List<Linedef> sectorLinedefs = new List<Linedef>();
                foreach (Sidedef sd in s.Sidedefs)
                    foreach (Linedef ld in sd.Linedefs)
                    {
                        if (sectorLinedefs.Contains(ld))
                            continue;
                        
                        sectorLinedefs.Add(ld);
                    }

                //now we want to sort them based on which line connects to which line
                //so we ned to mathc worldUp end points to start points.
                List<Stack<int>> lumps = new List<Stack<int>>();

                Stack<int> lump = new Stack<int>();
                                   
                lump.Push(sectorLinedefs[0].VertPairIndex[0]);
                lump.Push(sectorLinedefs[0].VertPairIndex[1]);
                sectorLinedefs.RemoveAt(0);

                while (sectorLinedefs.Count > 0)
                {     
                    int lastVertInd = lump.Peek();
                    Boolean found = false;
                    for (int i = 0; i < sectorLinedefs.Count; ++i)
                    {
                        //match the end vert of our current line
                        //to either vert of the next line. line verts are not ordered, so we have to try both.
                        //then add the next vert in the frontVerts
                        if (lastVertInd == sectorLinedefs[i].VertPairIndex[1])
                        {
                            lump.Push(sectorLinedefs[i].VertPairIndex[0]);
                            sectorLinedefs.RemoveAt(i);
                            found = true;
                            break;
                        }
                        if (lastVertInd == sectorLinedefs[i].VertPairIndex[0])
                        {
                            lump.Push(sectorLinedefs[i].VertPairIndex[1]);
                            sectorLinedefs.RemoveAt(i);
                            found = true;
                            break;
                        }                                                   
                    }
                    if (found == false)
                    {
                        //we didnt find the next frontVerts. this is likely because we have 
                        //sectors inside of this one and all our linedefs dont connect
                        //add this lump, and continue on
                        lumps.Add(lump);
                        lump = new Stack<int>();
                        
                        lump.Push(sectorLinedefs[0].VertPairIndex[0]);
                        lump.Push(sectorLinedefs[0].VertPairIndex[1]);
                        sectorLinedefs.RemoveAt(0);
                    }
                }
                //add our final lump to the lumps list
                lumps.Add(lump);

                //now, need to go throughthe list of lumps and see if any are actually internal loops that connect to
                //another lump.
                //for args, an actual lump is like a sector fully incosed, so it makes a hole
                //an internal loop is like: 4 lindefs have verts at the same lookAt, so we have a hole
                //but its connected to the outside, so our linedf following algorithm might not follow itproperly
                //go through each vert of each lump and see if it is the same as an othe rvert in any other lump

                //now that our linedefs are in order, lets pop em off and add verts ot the sector
                foreach(Stack<int> vertInd in lumps)
                {
                    List<Vertex> lumpVerts = new List<Vertex>();
                    while (vertInd.Count > 0)
                    {
                        int popped = vertInd.Pop();
                        lumpVerts.Add(Verts[popped]);
                    }
                    s.ContourVerts.Add(lumpVerts);
                }
            }

            //we should be good now.
        }

    }
}

